package com.leyou.order.util;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.order.config.PayConfig;
import com.leyou.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import static com.github.wxpay.sdk.WXPayConstants.*;

@Slf4j
@Component
public class PayHelper {

    @Autowired
    private WXPay wxPay;

    @Autowired
    private PayConfig payConfig;

    @Autowired
    private OrderService orderService;

    /**
     * 向微信发起请求，获取订单支付 url
     * @param orderId
     * @param totalPay
     * @param desc
     * @return
     */
    public String createOrder(Long orderId, Long totalPay, String desc) {
        try {
            Map<String, String> data = new HashMap<>();
            // 商品描述
            data.put("body", desc);
            // 订单号
            data.put("out_trade_no", orderId.toString());
            // 货币
            data.put("fee_type", "CNY");
            // 金额，单位是分
            data.put("total_fee", totalPay.toString());
            // 调用微信支付的终端IP（乐优商城的IP）
            data.put("spbill_create_ip", "127.0.0.1");
            // 回调地址，付款成功后的接口
            data.put("notify_url", payConfig.getNotifyUrl());
            // 交易类型为扫码支付
            data.put("trade_type", "NATIVE");

            data.forEach((key, value) -> System.out.println(key + "\t:" + value));

            // 利用 WXPay 工具，完成下单
            Map<String, String> result = this.wxPay.unifiedOrder(data);

            result.forEach((key, value) -> System.out.println(key + "\t:" + value));

            // 判断通信和业务标识
            isSuccess(result);

            // 返回结果
            String url = result.get("code_url");
            return url;
        } catch (Exception e) {
            log.error("[微信下单] 订单创建失败，orderId：{}", orderId, e);
            return null;
        }
    }

    /**
     * 订单创建通信 & 业务校验
     * @param result
     */
    public void isSuccess(Map<String, String> result) {
        // 判断通信标识
        String returnCode = result.get("return_code");
        if (FAIL.equals(returnCode)) {
            // 通信失败
            log.error("[微信下单] 微信下单通信失败，失败原因：{}", result.get("return_msg"));
            throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
        }

        // 判断业务标识
        String resultCode = result.get("result_code");
        if (FAIL.equals(resultCode)) {
            // 通信失败
            log.error("[微信下单] 微信下单业务失败，错误码：{}，错误原因：{}",
                    result.get("err_code"), result.get("err_code_des"));
            throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
        }
    }

    /**
     * 签名校验
     * @param data
     * @return
     */
    public boolean isValidSign(Map<String, String> data) {
        // 再次生成签名
        try {
            String sign1 = WXPayUtil.generateSignature(data, payConfig.getKey(), SignType.HMACSHA256);
            String sign2 = WXPayUtil.generateSignature(data, payConfig.getKey(), SignType.MD5);

            // 与当前签名比较
            String sign = data.get("sign");
            if (!StringUtils.equals(sign, sign1) && !StringUtils.equals(sign, sign2)) {
                throw new LyException(ExceptionEnum.INVALID_SIGN_ERROR);
            }

            return true;
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.INVALID_SIGN_ERROR);
        }
    }

    /**
     * 向微信发起请求，查询订单状态
     * @param orderId
     */
    public PayStateEnum queryPayState(Long orderId) {
        try {
            // 封装请求参数
            Map<String, String> data = new HashMap<>();
            // 订单号
            data.put("out_trade_no", orderId.toString());
            // 查询订单状态
            Map<String, String> result = wxPay.orderQuery(data);

            String state = result.get("trade_state");
            if (SUCCESS.equals(state)) {
                // 支付成功
                // 手动回调，结果解析
                orderService.handleNotify(result);

                return PayStateEnum.SUCCESS;
            }

            if ("NOTPAY".equals(state) || "USERPAYING".equals(state)) {
                return PayStateEnum.NOT_PAY;
            }

            return PayStateEnum.FAIL;
        } catch (Exception e) {
            return PayStateEnum.NOT_PAY;
        }
    }
}
